package main.userInterface.critterui.critterviewer;

import main.model.critters.CritterFactory;
import main.model.critters.genetics.Chromosome;
import main.model.critters.genetics.DefaultMorphology;
import main.model.critters.genetics.Morphology;
import main.model.critters.genetics.Sex;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.geom.GeneralPath;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

public class CritterCanvas extends JPanel {
	private Color LINE = Color.white;
	private Color BLACK = Color.black;

    BodyParts bodyParts;
    BufferedImage img = null;

	private double scale = 1;

    public void newCritter(){
        Chromosome cX = CritterFactory.randomChromosome();
        Chromosome cY = CritterFactory.randomChromosome();
        bodyParts = new BodyParts(new DefaultMorphology(Sex.FEMALE , cX, cY));
        repaint();
    }

    private Drawing drawing;
	public CritterCanvas() {
        bodyParts = new BodyParts(null);
        newCritter();
        try {
            img = ImageIO.read(new File("dog.jpg"));
        } catch (IOException e) {
            e.printStackTrace();
        }
		setBackground(BLACK);
	}

    public void putDrawing(Drawing drawing){
        this.drawing = drawing;
    }
	
	public void paintComponent(Graphics g){
		super.paintComponent(g);
		Graphics2D g2 = (Graphics2D)g;
        //g2.drawImage(img , 0,0, null);
        g2.setColor(LINE);
        drawDrawing(g2);

        buildRelativePoints(g2);
        //buildAbsolutePoints(g2);
	}

    public void buildAbsolutePoints(Graphics2D g2){
        //g2.drawImage(img , 0,0, null);
        g2.setColor(LINE);
        drawDrawing(g2);
        Color skin =  Color.red;
        Color darkSkin = skin.darker().darker();
        Color bone = Color.white;
        //GeneralPath body = polygon(bodyParts.getBody()) ;

        // makeParts(g2 , polygon(buildFrontFarLeg()) , darkSkin);
        // makeParts(g2 , polygon(bodyParts.getBackFarLeg()) , darkSkin);
        // makeParts(g2 , polygon(buildNeck()) , skin );
        // makeParts(g2 , polygon(buildBody()));
        // makeParts(g2 , polygon(buildTail()));
        // makeParts(g2 , polygon(bodyParts.getFrontNearLeg()));
        // makeParts(g2 , polygon(bodyParts.getBackNearLeg()));

        makeParts(g2 , polygon(buildBackEar()) , darkSkin);
        makeParts(g2 , polygon(buildHead()) , skin);
        makeParts(g2 , polygon(buildHorn()) , bone);
        makeParts(g2 , polygon(buildTusk()) , bone);
        makeParts(g2 , polygon(buildJaw()) , skin);
        makeParts(g2 , polygon(buildEye()) , Color.BLACK);
        makeParts(g2 , polygon(buildEarFront()) , skin );
    }

    public void buildRelativePoints(Graphics2D g2){

        g2.setColor(LINE);
        drawDrawing(g2);

        Color skin =  Color.blue;
        Color darkSkin = skin.darker().darker();
        Color bone = Color.white;


        makeParts(g2 , polygon(bodyParts.getFrontFarLeg()) , darkSkin);
        makeParts(g2 , polygon(bodyParts.getBackFarLeg()) , darkSkin);
        makeParts(g2 , polygon(bodyParts.getNeck()) , skin);
        makeParts(g2 , polygon(bodyParts.getBody()) , skin);
        makeParts(g2 , polygon(buildTail()) , skin);
        makeParts(g2 , polygon(bodyParts.getFrontNearLeg()) , skin);
        makeParts(g2 , polygon(bodyParts.getBackNearLeg()) , skin);
        makeParts(g2, polygon(bodyParts.getFarEar()), darkSkin);
        makeParts(g2 , polygon(bodyParts.getHead())  , skin);
        // makeParts(g2 , polygon(buildHorn()) , bone);
        // makeParts(g2 , polygon(buildTusk()) , bone);
        makeParts(g2 , polygon(bodyParts.getJaw()) , skin);
        makeParts(g2 , polygon(bodyParts.getEye()) , Color.BLACK);
        makeParts(g2 , polygon(bodyParts.getNearEar())  , skin);
    }


    private void makeParts(Graphics2D g2 , GeneralPath polygon){
        makeParts(g2 , polygon , Color.BLUE);
    }

    private void makeParts(Graphics2D g2 , GeneralPath polygon , Color color){
        g2.setColor(color);
        g2.fill(polygon);
        g2.setColor(Color.WHITE);
        g2.draw(polygon);
    }

    private void drawDrawing(Graphics2D g2){
        GeneralPath polygonPath = new GeneralPath();

        if(drawing.points.size() > 0){
            drawing.points.get(0);
            polygonPath.moveTo(drawing.points.get(0).getX().getX() , drawing.points.get(0).getX().getY());
            polygonPath.quadTo(drawing.points.get(0).getY().getX(), drawing.points.get(0).getY().getY(),
                    drawing.points.get(0).getArc().getX(), drawing.points.get(0).getArc().getY());

            for(int i = 0 ; i < drawing.points.size() ; i++){
                polygonPath.quadTo(drawing.points.get(i).getY().getX() , drawing.points.get(i).getY().getY(),
                        drawing.points.get(i).getArc().getX() , drawing.points.get(i).getArc().getY());
            }
            g2.draw(polygonPath);
        }
    }


    private void doubleRemapper(double[][] array , double minx, double miny){

        for(int a = 0 ; a < array.length ; a++){
            if(a == 0){

                array[0][0] = array[0][0] - minx;
                array[0][1] = array[0][1] - miny;
            }else {
                array[a][0] = array[a][0] - minx;
                array[a][1] = array[a][1] - miny;
                array[a][2] = array[a][2] - minx;
                array[a][3] = array[a][3] - miny;
            }
        }
        System.out.println();
        for(int a = 0; a < array.length ; a++){
            System.out.print("{ ");
            for(int b = 0; b < array[a].length ; b++){
                System.out.print(array[a][b]);
                if(b+1 < array[a].length )System.out.print(" , ");
            }
            System.out.print(" },");
            System.out.println();
        }

    }

    private void moveArrayToZero(double[][] array){

        double minx = 100000000;
        double miny = 100000000;
        double maxx = 0;
        double maxy = 0;

        for(int a = 0 ; a < array.length ; a++){
            if(a == 0){
                minx = array[0][0];
                maxx = array[0][0];
                miny = array[0][1];
                minx = array[0][1];
            }else {
                if(array[a][0] < minx)
                    minx = array[a][0];
                if(array[a][0] > maxx)
                    maxx = array[a][0];
                if(array[a][1] < miny)
                    miny = array[a][1];
                if(array[a][1] > maxy)
                    maxy = array[a][1];

                if(array[a][2] < minx)
                    minx = array[a][2];
                if(array[a][2] > maxx)
                    maxx = array[a][2];
                if(array[a][3] < miny)
                    miny = array[a][3];
                if(array[a][3] > maxy)
                    maxy = array[a][3];
            }
        }

        System.out.println("MINX = "+minx+" , MINY = "+miny+" , MAXX = "+maxx+" , MAXY = "+maxy);

        doubleRemapper(array , minx , miny);
    }

    private double[][] buildNeck(){

        //head neck 	93 , 93
        //neck body 	128 , 138
        double[][] neck = {{178 , 116},
                {151 , 106 , 142 , 102},
                {131 , 91 , 116 , 82},
                {103 , 84 , 112 , 72},
                {94 , 72 , 76 , 88},
                {76 , 103 , 83 , 123},
                {93 , 142 , 100 , 166}};
        return neck;
    }
    private double[][] buildHead(){
        //front ear	95 , 62
        //tusk       	48 , 111
        //ear back	81 , 57
        double [][] head = {{115 , 92},
                {123 , 72 , 105 , 55},
                {87 , 47 , 63 , 58},
                {54 , 67 , 51 , 80}, //start muzzle
                {44 , 89 , 26 , 94},
                {20 , 98 , 27 , 106},
                {35 , 109 , 42 , 113},
                {58 , 104 , 71 , 100}};
        return head;
    }
    private double[][] buildEye(){
        double[][] eye = {{67 , 65},
                {74 , 65 , 80 , 68},
                {76 , 74 , 65 , 72},
                {66 , 71 , 67 , 65}};
        return eye;
    }
    private double[][] buildTusk(){

        //tusk       	48 , 111
        double[][] tusk = {{47 , 113},
                {40 , 108 , 39 , 102},
                {45 , 108 , 55 , 108}};
        return tusk;
    }
    private double[][] buildJaw(){
        double[][] jaw = {{70 , 98},
            {58 , 103 , 48 , 106},
            {44 , 109 , 40 , 112},
            {37 , 117 , 48 , 123},
            {57 , 118 , 66 , 111},
            {77 , 111 , 89 , 103},
            {96 , 94 , 96 , 87 }};
        return jaw;
    }
    private double[][] buildHorn(){
        double[][] horn = {{33 , 94},
            {27 , 87 , 24 , 72},
            {25 , 58 , 30 , 50},
            {30 , 63 , 34 , 70},
            {41 , 78 , 94/2 , 170/2},
            {42 , 92 , 33 , 94}};
        return horn;
    }
    private double[][] buildEarFront(){
        //front ear	95 , 62
        double [][] frontEar = {{83 , 59},
                {83 , 42 , 95 , 24},
                {101 , 38 , 112 , 51},
                {108 , 64 , 96 , 72 }};
        return frontEar;
    }
    private double[][] buildBackEar(){
        //ear back	81 , 57
        double[][] ear = {{77 , 59},
                {74 , 47 , 73 , 26},
                {78 , 20 , 86 , 37},
                {92 , 44 , 95 , 53},
                {95 , 63 , 85 , 67}};
        return ear;
    }
    private double[][] buildTail(){
        //tail 		342 , 189
        double[][] tail = {{342 , 171},
                {359 , 184 , 367 , 193},
                {380 , 217 , 396 , 234},
                {414 , 242 , 432 , 240},
                {441 , 235 , 448 , 222},
                {454 , 252 , 438 , 264},
                {415 , 271 , 395 , 263},
                {372 , 257 , 353 , 235},
                {343 , 220 , 331 , 206}};
                        return tail;
    }

	private GeneralPath polygon(double p[][]){
		int X = 0; int Y = 1;
		int QX = 2; int QY = 3;
		int CX = 4; int CY = 5;
		GeneralPath polygonPath = new GeneralPath();
		
		polygonPath.moveTo (p[0][X]*scale, p[0][Y]*scale);
		for (int i = 1; i < p.length; i++) {
			if(p[i].length == 2){
				polygonPath.lineTo(p[i][X], p[i][Y]);
			}else if(p[i].length == 4){
				polygonPath.quadTo(p[i][X]*scale, p[i][Y]*scale, p[i][QX]*scale, p[i][QY]*scale);
			}else if(p[i].length ==6){
				polygonPath.curveTo(p[i][QX], p[i][QY], p[i][CX], p[i][CY], p[i][X], p[i][Y]);
			}
		}
		return polygonPath;
	}
}
